home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / presto / prest_04.lha / src / unix / scheduler_sig.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-08-08  |  8.1 KB  |  308 lines

  1. /*
  2.  * Signal handling nonsense.  Signals need to be dealt with in their
  3.  * own class.  Suggestions anyone?
  4.  *
  5.  * Main chore here is to catch all nasty signals in the parent so we can kill
  6.  * off all the children processes so they don't loop forever.  (if the parent
  7.  * dies while "busy", he never gets unbusy) We can't protect against
  8.  * noncatchable signals in the parent, specificall SIGKILL.  The best we can do
  9.  * is in the children, check every once in a while if the current ppid is not
  10.  * init.  Really need a SIGPARENT  (SIGPARNT?) to notify the children that its
  11.  * parent has changed.
  12.  *
  13.  * Last modified:
  14.  *            bnb 
  15.  *            1/27/88 to create
  16.  */
  17.  
  18.  
  19. #include <sys/types.h>
  20. #include <sys/wait.h>
  21. #include <signal.h>
  22. #include <osfcn.h>
  23. #include "presto.h"
  24.  
  25.  
  26. //
  27. // Route all normal default signals through the parent handler.  Children
  28. // should not be handling signals other than those WHICH are defined
  29. // by presto.  The whole idea of signals in this environment is strange.
  30. // Signals are for processes.  Signals should be for threads.
  31. //
  32.  
  33.  
  34. typedef int    (*PFSigHandler)(int, int, sigcontext*);
  35. int    schedulerSigHandler(int sig, int code, struct sigcontext *scp);
  36. int    schedulerReapChild(int sig, int code, struct sigcontext *scp);
  37.  
  38. #ifdef sequent
  39. static  struct sigvec HAND_vec = {schedulerSigHandler, sigmask(SIGCHLD),1};
  40. static  struct sigvec CHLD_vec = {schedulerReapChild, 0, 1};
  41. #endif sequent
  42. #ifdef sun
  43. static  struct sigvec HAND_vec = {schedulerSigHandler, sigmask(SIGCHLD),0};
  44. static  struct sigvec CHLD_vec = {schedulerReapChild, 0, 0};
  45. #endif sun
  46. #ifdef vax
  47. static  struct sigvec HAND_vec = {schedulerSigHandler, sigmask(SIGCHLD),0};
  48. static  struct sigvec CHLD_vec = {schedulerReapChild, 0, 0};
  49. #endif vax
  50.  
  51. // default handler
  52. static struct sigvec DFL_vec = {(PFSigHandler)SIG_DFL, 0, 0};
  53.  
  54. #ifdef sequent // force kernel sigvec  to be called
  55. #define SIGVEC_OS    _sigvec
  56. #endif sequent
  57.  
  58. #ifdef sun
  59. #define SIGVEC_OS    sigvec
  60. #endif sun
  61.  
  62. #ifdef vax
  63. #define SIGVEC_OS    sigvec
  64. #endif vax
  65.  
  66. extern int SIGVEC_OS(int, struct sigvec*, struct sigvec*);
  67.  
  68. //
  69. // Force the parent to come through here on all signals that
  70. // are "unpleasant" and not already handled.
  71. //
  72. void
  73. Scheduler::initsighandlers(int setupdefaults)
  74. {
  75.     struct sigvec sv;
  76.     int sig;
  77.  
  78.     if (setupdefaults == 0) {
  79.         SIGVEC_OS(SIGCHLD, &CHLD_vec, (struct sigvec*)0);
  80.         return;
  81.     } else if (setupdefaults < 0) {
  82.         /*
  83.          * Don't be bothered by exiting children.
  84.          */
  85.         SIGVEC_OS(SIGCHLD, &DFL_vec, (struct sigvec*)0);    
  86.         return;
  87.     }
  88.  
  89.     for (sig = 1; sig < NSIG; sig++)    {
  90.         switch (sig) {
  91.         case    SIGSTOP:
  92.         case    SIGTSTP:
  93.         case    SIGTTIN:
  94.         case    SIGTTOU:
  95.         case    SIGURG:
  96.         case    SIGCONT:
  97.         case    SIGIO:
  98.         case    SIGCHLD:
  99.         case    SIGWINCH:
  100.             continue;
  101.         default:
  102.             if (SIGVEC_OS(sig, 0, &sv) < 0)
  103.                 continue;     // might make some noise
  104.             if (sv.sv_handler != (PFSigHandler)SIG_DFL)
  105.                 continue;
  106.             (void) SIGVEC_OS(sig, &HAND_vec, (struct sigvec *)0);
  107.         }
  108.     }
  109. }
  110.  
  111. //
  112. // Parent proc comes here when it is time to kill everyone off.
  113. // We do not necessarily get a core dump and we do not terminate
  114. // ourselves.  The caller must do that.  We just kill off everybody else.
  115. //
  116. // if sig is negative, then we are not the parent, but a child proc
  117. // who says KILL EVERYONE and forgewt about  being polite.  Child procs
  118. // should use this when they detect that their parent is dead, but
  119. // realize that everyone else must die also.  If the root proc does this,
  120. // nobody will be cleaned up after, but it would still work.
  121. //
  122. // Killer siblings can end up killing one another more than they need
  123. // too, since we don't bother to mark thisproc as reaped before it
  124. // nukes itself.  It doesn't matter, in the worst case, some guys get killed
  125. // more than once.
  126. //
  127. void
  128. Scheduler::abort(int sig)
  129. {
  130.     int pnum;                // proc num of dying proc
  131.     int tpid;                // pid of dying proc
  132.     union wait status;            // and how they died
  133.     int    waitforchild = 1;        // presume we are parent
  134.  
  135.     if (sig < 0)    {
  136.         sig = -sig;
  137.         waitforchild = 0;
  138.     } else    {
  139.         if (thisproc != sc_p_procs[0]) {    // non root proc
  140.             kill(thisproc->pid(), sig);    // just dies, parent
  141.         }                    // should clean up
  142.         //
  143.         // only root process gets this far
  144.         //
  145.         // no interruptions please
  146.         SIGVEC_OS(SIGCHLD, &DFL_vec, (struct sigvec*)0);    
  147.     }
  148.     for (pnum = 0; pnum < sc_p_numschedulers; pnum++)    {
  149.         Process *p = sc_p_procs[pnum];
  150.  
  151.         if (p == thisproc)        // we've got a JOB to do!
  152.             continue;
  153.  
  154.         if (waitforchild && p->state()&S_REAPED)// not sibling killer
  155.             continue;            // and already reaped
  156.  
  157.         //
  158.         // Could either pass sig along to all children, in which
  159.         // case we might end up with tons of core files, or
  160.         // just say "to hell with it", one core file is enough.
  161.         // All we care about here is that everybody else stops
  162.         //
  163.  
  164.         while (kill( p->pid(), SIGKILL) == 0)
  165.             continue;    // force him to die
  166.  
  167.         if (waitforchild == 0)    // can't reap sibling
  168.             continue;
  169.  
  170.         //
  171.         // pick up dead procs.  Deal with the chance that
  172.         // multiple guys may die while we are doing this
  173.         //
  174.         do {
  175.             tpid = wait((int*)(&status));
  176.             if (tpid >= 0)    {
  177.                 int procnum = pidtoprocnum(tpid);
  178.                 if (procnum >= 0)
  179.                     sc_p_procs[procnum]->setstate(S_REAPED);
  180.                 if (status.w_coredump)
  181.                     storecore(pidtoprocnum(tpid));
  182.             }
  183.         } while (tpid != p->pid() && tpid >= 0);
  184.     }
  185.     //
  186.     // You may see this message more than once.  Can't lock though
  187.     // cuz we could get killed in the lock, and then nobody else
  188.     // could proceed.  
  189.     //
  190.     if (waitforchild == 0)
  191.         cerr << "Sibling ";
  192.     cerr << "Scheduler aborting with signal " << sig << "\n";
  193.     (void)SIGVEC_OS(sig, &DFL_vec, (struct sigvec*)0);
  194.     (void)kill(thisproc->pid(), sig);
  195.     // NOT REACHED (definitely)        
  196. }
  197.  
  198. //
  199. // Write a core file.  Hope we get to move it before someone else
  200. // dumps.  The first core file that dumps is called simply "core.First",
  201. // all the rest are appended with the number of the processor
  202. // that dumped.
  203. // If you end up with a core.-1 file, then something bizarre happened to the
  204. // pid to procnum mapping function and you may be missing some core files.
  205. // As they say in te compouter business "This should never happen."
  206. //
  207.  
  208. void
  209. Scheduler::storecore(int pnum)                             
  210. {
  211.     int rename(char*, char*);
  212.     static int firstdump = 1;
  213.     char cname[16];
  214.  
  215.     if (firstdump)    {
  216.         sprintf(cname,"core.First");
  217.         firstdump = 0;
  218.     } else    {
  219.         sprintf(cname,"core.%d", pnum);
  220.     }
  221.     cerr << "Caught core file " << (char*)&cname[0] << "\n";
  222.     (void)rename("core", cname);
  223. }
  224.  
  225. int
  226. Scheduler::pidtoprocnum(int pid)
  227. {
  228.     int p;
  229.     for (p = 0; p < sc_p_numschedulers; p++)
  230.         if (pid == sc_p_procs[p]->pid())
  231.             return p;    // presto pid
  232.     return -1;
  233. }
  234.  
  235.  
  236. //
  237. // SIGCHLD handler.  If we are the root proc, clean up the child, abort
  238. // everyone else with the a clean signal.  We never return from 
  239. // schedulerSigHandler
  240. // unless we are already handloing some kind of a terminating signal.
  241. //
  242. int
  243. schedulerReapChild(int sig, int code, struct sigcontext *scp)
  244. {
  245.     union wait status;
  246.     int tpid;
  247.     int procnum;
  248.     int wait3(union wait*, int, int);
  249.  
  250.     if (sched == 0)
  251.         return 0;        //???
  252.     if (thisproc != sched->sc_p_procs[0])    
  253.         return 0;    // who else and why would would it be caught?
  254.  
  255.     tpid = wait3(&status, WNOHANG|WUNTRACED, 0);
  256.  
  257.     if (tpid <= 0)
  258.         return 0 ;        // spurious?
  259.     if (WIFSTOPPED(status))        // child could pause
  260.         return 0;
  261.  
  262.     cerr << "Process " << tpid ;    
  263.     if (WIFSIGNALED(status))    {
  264.         procnum = sched->pidtoprocnum(tpid);
  265.         if (procnum >= 0)
  266.             sched->sc_p_procs[procnum]->setstate(S_REAPED);
  267.  
  268.         if (status.w_coredump)
  269.             sched->storecore(procnum);
  270.         cerr <<  " killed " << status.w_termsig  << "\n";
  271.     } else        // must have just exited
  272.         cerr << " exited " << status.w_termsig << "\n";
  273.     //
  274.     // don't bother to core dump everyone else
  275.     //
  276.     schedulerSigHandler(SIGKILL, code, scp);
  277.     //
  278.     //     NOT REACHED  (well... maybe)
  279.     //
  280.     sig=sig;
  281.     return 0;
  282. }
  283.  
  284. //
  285. //
  286. // parent comes here when we get a "default" signal
  287. //
  288. int 
  289. schedulerSigHandler(int sig, int code, struct sigcontext *scp)
  290. {    
  291.     static int aborting = 0;        // avoid looping on signals
  292.     if (sched)        {        // once the axe is in motion
  293.         if (aborting == 0)    {
  294.             aborting++;
  295.             sched->abort(sig);
  296.             // NOT REACHED
  297.         } else
  298.             return 0;
  299.     } else    {
  300.         // sig ourselves
  301.         (void)SIGVEC_OS(sig, &DFL_vec, (struct sigvec*)0);
  302.         (void)kill(getpid(), sig);
  303.         // NOT REACHED
  304.     }
  305.     code=code;scp=scp;
  306.     return 0;
  307. }
  308.